var map;
var highlightControl;
var selectControl;

var proj3857   = new OpenLayers.Projection("EPSG:3857");
var proj900913 = new OpenLayers.Projection("EPSG:900913");
var proj4326   = new OpenLayers.Projection("EPSG:4326");

var toolTipQueue  = [];
var knownToolTips = [];

var searchLimitPerPage = 20;
var searchStart        = 1;
var activeSearches     = 0;

function init() {
  var loadingMask = Ext.get('loading-mask');
  var loading = Ext.get('loading');

  //Hide loading message
  loading.fadeOut({duration : 0.2,remove : true});

  //Hide loading mask
  loadingMask.setOpacity(0.9);
  loadingMask.shift({
     xy       : loading.getXY()
    ,width    : loading.getWidth()
    ,height   : loading.getHeight()
    ,remove   : true
    ,duration : 1
    ,opacity  : 0.1
    ,easing   : 'bounceOut'
  });

  Ext.QuickTips.init();
  var sto = new Ext.data.XmlStore({
    proxy       : new Ext.data.HttpProxy({
       method  : 'POST'
      ,url     : 'post.php?t=' + new Date().getTime() + '&ns=csw|gmi|gml|srv|gmd|gco&url=' + encodeURIComponent(catalogUrl)
      ,timeout : 120000
    })
    ,autoLoad      : false
    ,record        : 'gmd_MD_Metadata'
    ,totalProperty : 'csw_SearchResults@numberOfRecordsMatched'
    ,fields        : [
       {name : 'title'          ,mapping : 'gmd_identificationInfo > gmd_MD_DataIdentification > gmd_citation > gmd_CI_Citation > gmd_title > gco_CharacterString'}
      ,{name : 'provider'       ,mapping : 'gmd_identificationInfo > gmd_MD_DataIdentification > gmd_citation > gmd_CI_Citation > gmd_citedResponsibleParty > gmd_CI_ResponsibleParty > gmd_organisationName > gco_CharacterString'}
      ,{name : 'abstract'       ,mapping : 'gmd_identificationInfo > gmd_MD_DataIdentification > gmd_abstract > gco_CharacterString'}
      ,{name : 'cswId'          ,mapping : 'gmd_fileIdentifier > gco_CharacterString'}
      ,{name : 'bboxWest'       ,mapping : 'gmd_identificationInfo > gmd_MD_DataIdentification > gmd_extent > gmd_EX_Extent > gmd_geographicElement > gmd_EX_GeographicBoundingBox > gmd_westBoundLongitude > gco_Decimal'}
      ,{name : 'bboxEast'       ,mapping : 'gmd_identificationInfo > gmd_MD_DataIdentification > gmd_extent > gmd_EX_Extent > gmd_geographicElement > gmd_EX_GeographicBoundingBox > gmd_eastBoundLongitude > gco_Decimal'}
      ,{name : 'bboxSouth'      ,mapping : 'gmd_identificationInfo > gmd_MD_DataIdentification > gmd_extent > gmd_EX_Extent > gmd_geographicElement > gmd_EX_GeographicBoundingBox > gmd_southBoundLatitude > gco_Decimal'}
      ,{name : 'bboxNorth'      ,mapping : 'gmd_identificationInfo > gmd_MD_DataIdentification > gmd_extent > gmd_EX_Extent > gmd_geographicElement > gmd_EX_GeographicBoundingBox > gmd_northBoundLatitude > gco_Decimal'}
      ,{name : 'minT'           ,mapping : 'gmd_identificationInfo > gmd_MD_DataIdentification > gmd_extent > gmd_EX_Extent > gmd_temporalElement > gmd_EX_TemporalExtent > gmd_extent > gml_TimePeriod > gml_beginPosition'}
      ,{name : 'maxT'           ,mapping : 'gmd_identificationInfo > gmd_MD_DataIdentification > gmd_extent > gmd_EX_Extent > gmd_temporalElement > gmd_EX_TemporalExtent > gmd_extent > gml_TimePeriod > gml_endPosition'}
      ,{name : 'services'       ,convert : (function(){
        return function(v,n) {
          return new Ext.data.XmlReader({
             record : 'gmd_identificationInfo > srv_SV_ServiceIdentification'
            ,fields : [
               {name : 'type'    ,mapping : 'srv_serviceType > gco_LocalName'}
              ,{name : 'url'     ,mapping : 'srv_containsOperations > srv_SV_OperationMetadata > srv_connectPoint > gmd_CI_OnlineResource > gmd_linkage > gmd_URL'}
            ]
          }).readRecords(n).records;
        }
      })()}
      ,{name : 'dimensions'     ,convert : (function(){
        return function(v,n) {
          return new Ext.data.XmlReader({
             record : 'gmd_contentInfo > gmi_MI_CoverageDescription > gmd_dimension'
            ,fields : [
              {name : 'name',mapping : 'gmd_MD_Band > gmd_descriptor > gco_CharacterString'}
            ]
          }).readRecords(n).records;
        }
      })()}
    ]
    ,listeners  : {
      beforeload : function(sto,o) {
        Ext.getCmp('searchResultsGridPanel').getEl().mask('<table><tr><td>Loading...&nbsp;</td><td><img src="js/ext-3.3.0/resources/images/default/grid/loading.gif"></td></tr></table>','mask');
        activeSearches++;
        sto.setBaseParam('xmlData',buildFilter(o.params.limit,o.params.start));
      }
      ,load      : function(sto) {
        syncMapWithResults(sto);
      }
    }
  });

  new Ext.Viewport({
     layout : 'border'
    ,items  : [
      new Ext.grid.GridPanel({
         id      : 'searchResultsGridPanel'
        ,cls     : 'chromeNoHorizontalScrollbar'
        ,region  : 'west'
        ,width   : 400
        ,split   : true
        ,store   : sto
        ,sm      : new Ext.grid.RowSelectionModel({
           singleSelect : true
          ,listeners    : {
            beforerowselect : function() {
              // don't allow normal row selection behavior
              return false;
            }
            ,rowselect : function(sm,idx,rec) {
              selectControl.unselectAll();
              for (var i = 0; i < selectControl.layer.features.length; i++) {
                if (selectControl.layer.features[i].attributes.id == rec.id) {
                  selectControl.select(selectControl.layer.features[i]);
                  var g = selectControl.layer.features[i].geometry.clone();
                  g.transform(proj900913,proj4326);
                  var bbox = g.getBounds().toArray();
                  map.zoomToExtent(new OpenLayers.Bounds(
                     Number(bbox[0]) - 2
                    ,Number(bbox[1]) - 2
                    ,Number(bbox[2]) + 2
                    ,Number(bbox[3]) + 2
                  ).transform(proj4326,proj900913));
                }
              }
            }
          }
        })
        ,columns : [
          {dataIndex : 'title',id : 'title',renderer : function(val,p,rec) {
            var data = [];
            var dimensions = rec.get('dimensions');
            var dimSort = [];
            for (var j = 0; j < dimensions.length; j++) {
              dimSort.push(dimensions[j].get('name'));
            }
            dimSort.sort(function(a,b) {
              return a.toLowerCase().localeCompare(b.toLowerCase());
            });
            for (var j = 0; j < dimSort.length; j++) {
              var id = Ext.id();
              data.push([
                dimSort[j],dimSort[j]
              ]);
            }

            var d = '';
            var okMinT = new RegExp(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ$/).test(rec.get('minT'));
            var okMaxT = new RegExp(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ$/).test(rec.get('maxT'));
            if (okMinT && okMaxT) {
              if (isoDateToDate(rec.get('minT')).format('mmm d, yyyy') == isoDateToDate(rec.get('maxT')).format('mmm d, yyyy')) {
                d = isoDateToDate(rec.get('minT')).format('mmm d, yyyy');
              }
              else if (isoDateToDate(rec.get('minT')).format('yyyy') == isoDateToDate(rec.get('maxT')).format('yyyy')) {
                d = isoDateToDate(rec.get('minT')).format('mmm d') + ' - ' + isoDateToDate(rec.get('maxT')).format('mmm d, yyyy');
              }
              else {
                d = isoDateToDate(rec.get('minT')).format('mmm d, yyyy') + ' - ' + isoDateToDate(rec.get('maxT')).format('mmm d, yyyy');
              }
            }
            else if (okMinT) {
              d = 'from ' + isoDateToDate(rec.get('minT')).format('mmm d, yyyy');
            }
            else if (okMaxT) {
              d = 'to ' + isoDateToDate(rec.get('maxT')).format('mmm d, yyyy');
            }

            var svcHtml = [];
            var svc = rec.get('services');
            for (var i = 0; i < svc.length; i++) {
              svcHtml.push('<a href="' + svc[i].data.url + (new RegExp(/thredds opendap/i).test(svc[i].data.type) ? '.html' : '') + '" target=_blank>' + svc[i].data.type + '</a>');
            } 
            if (svcHtml.length > 0) {
              svcHtml = ['Data service(s): ',svcHtml.join(', ')];
            }

            var text = [];
            if (rec.get('abstract') != '') {
              text.push(rec.get('abstract'));
            }
            if (d != '') {
              text.push(d);
            }
            if (svcHtml.length > 0) {
              text.push(svcHtml.join(''));
            }

            var metadataU = '<a href="xsl2html.php?xsl=' + xsl + '&xml=' + xml + '&id=' + encodeURIComponent(rec.get('cswId')) + '&url=' + encodeURIComponent(catalogUrl) + '" target=_blank>' + (val != '' ? val : 'Title unavailable') + '</a>';
            if (new RegExp(/^___/).test(rec.get('cswId'))) {
              metadataU = val != '' ? val : 'Title unavailable';
            }
            return '<b>' + metadataU + '</a></b><p><br>' + text.join('<br><br>') + '</p>';
          }}
          ,{width : 142,align : 'center',renderer : function(val,p,rec) {
            var svc = rec.get('services');
            var getCaps = [];
            for (var i = 0; i < svc.length; i++) {
              if (new RegExp(/service=wms/i).test(svc[i].data.url)) {
                getCaps.push('<br><br><span class="x-grid3-td-title"><a href="javascript:goGetCaps(\'' + svc[i].data.url + '\',\'' + rec.get('cswId') + '\')">Map dataset(s)</a></span>');
              }
              else if (new RegExp(/service=sos/i).test(svc[i].data.url)) {
                getCaps.push('<br><br><span class="x-grid3-td-title"><a href="javascript:goGetCaps(\'' + svc[i].data.url + '\',\'' + rec.get('cswId') + '\')">Map observation(s)</a></span>');
              }
            }
            var bbox = [rec.get('bboxWest'),rec.get('bboxSouth'),rec.get('bboxEast'),rec.get('bboxNorth')];
            if (bbox[0] == '') {
              return '<img width=128 height=128 src="img/worldError.png" title="Boundaries not found" alt="Boundaries not found">' + getCaps.join('<br>');
            }
            else if (bbox[0] == bbox[2] && bbox[1] == bbox[3]) {
              return '<img style="border:1px solid #99BBE8" width=128 height=128 src="https://maps.googleapis.com/maps/api/staticmap?key=AIzaSyBuB8P_e6vQcucjnE64Kh2Fwu6WzhMXZzI&markers=' + bbox[1] + ',' + bbox[0] + '&zoom=10&size=128x128&sensor=false" title="Data location" alt="Data location">' + getCaps.join('<br>');
            }
            else if (bbox[0] == -180 && bbox[1] == -90 && bbox[2] == 180 && bbox[3] == 90) {
              return '<img width=128 height=128 src="img/world.png" title="Global boundaries" alt="Global boundaries">' + getCaps.join('<br>');
            }
            else {
              return '<img style="border:1px solid #99BBE8" width=128 height=128 src="https://maps.googleapis.com/maps/api/staticmap?key=AIzaSyBuB8P_e6vQcucjnE64Kh2Fwu6WzhMXZzI&path=weight:1|fillcolor:0x0000AA11|color:0x0000FFBB|' + bbox[1] + ',' + bbox[0] + '|' + bbox[1] + ',' + bbox[2] + '|' + bbox[3] + ',' + bbox[2] + '|' + bbox[3] + ',' + bbox[0] + '|' + bbox[1] + ',' + bbox[0] + '&size=128x128&sensor=false" title="Data boundaries" alt="Data boundaries">' + getCaps.join('<br>');
            }
          }}
        ]
        ,autoExpandColumn : 'title'
        ,hideHeaders      : true
        ,tbar   : [
          new Ext.ux.form.SearchField({
             emptyText       : 'Enter keywords to find data.'
            ,cls             : (Ext.isChrome || Ext.isSafari) ? 'chromeInput' : ''
            ,width           : 100
            ,border          : false
            ,id              : 'anyTextSearchField'
            ,paramName       : 'anyText'
            ,wrapFocusClass  : ''
            ,hasSearch       : true
            ,hideTrigger1    : false
            ,store           : sto
            ,onTrigger1Click : function() {
              if(this.hasSearch){
                this.reset();
                // having a tough time w/ the focus, so force a reset for emptyText
                this.setRawValue(this.emptyText);
                this.el.addClass(this.emptyClass);
                this.triggers[0].hide();
                this.hasSearch = false;
              }
            }
            ,onTrigger2Click : function() {
              var v = this.getRawValue();
              if(v.length < 1){
                this.onTrigger1Click();
              return;
              }
              var o = {start : 0,limit : searchLimitPerPage};
              if (this.store) {
                this.store.baseParams = this.store.baseParams || {};
                this.store.baseParams[this.paramName] = v;
                this.store.reload({params:o});
              }
              Ext.getCmp('anyTextSearchField').setRawValue(this.getRawValue());
              this.hasSearch = true;
              this.triggers[0].show();
            }
          })
          ,'->'
          ,{
             text    : 'Zoom to results'
            ,handler : function() {
              if (map.getLayersByName('queryHits')[0].features && map.getLayersByName('queryHits')[0].features.length > 0) {
                var bbox = new OpenLayers.Bounds();
                for (var i = 0; i < map.getLayersByName('queryHits')[0].features.length; i++) { 
                  var b = map.getLayersByName('queryHits')[0].features[i].geometry.getBounds();
                  if (!(isNaN(b.bottom) || isNaN(b.left) || isNaN(b.top) || isNaN(b.right))) {
                    bbox.extend(b);
                  }
                }
                if (!(isNaN(bbox.bottom) || isNaN(bbox.left) || isNaN(bbox.top) || isNaN(bbox.right))) {
                  map.zoomToExtent(bbox);
                }
              }
            }
          }
          ,' '
          ,{
             text         : 'Sync with map'
            ,id           : 'buttonSyncWithMap'
            ,allowDepress : true
            ,enableToggle : true
            ,handler      : function(but) {
              if (Ext.getCmp('anyTextSearchField').getValue() != '') {
                Ext.getCmp('anyTextSearchField').onTrigger2Click();
              }
            }
          }
        ]
        ,bbar            : new Ext.PagingToolbar({
           pageSize    : searchLimitPerPage
          ,store       : sto
          ,id          : 'searchResultsPagingToolbar'
          ,displayInfo : true
          ,displayMsg  : 'Results {0} - {1} of {2}'
          ,emptyMsg    : 'No results to display'
        })
        ,listeners : {
          bodyresize : function(p,w,h) {
            cmp = Ext.getCmp('anyTextSearchField');
            if (cmp) {
              cmp.setWidth(w - 200);
            }
          }
          ,rowclick : function(g,idx,e) {
            // don't select the row if a user clicks on a link
            if (!e.getTarget().href) {
              var sm = g.getSelectionModel();
              var rec = g.getStore().getAt(idx);
              sm.fireEvent('rowselect',sm,idx,rec);
            }
          }
          ,mouseover : function(e,t) {
            var row = this.getView().findRowIndex(t);
            if (row >= 0) {
              var rec = this.getStore().getAt(row);
              if (rec) {
                for (var i = 0; i < highlightControl.layer.features.length; i++) {
                  if (highlightControl.layer.features[i].attributes.id == rec.id) {
                    highlightControl.highlight(highlightControl.layer.features[i]);
                  }
                }
              }
            }
          }
          ,mouseout : function(e,t) {
            for (var i = 0; i < highlightControl.layer.features.length; i++) {
              highlightControl.unhighlight(highlightControl.layer.features[i]);
            }
            // make sure to keep a selected row hilit correctly
            var s = this.getSelectionModel().getSelections();
            for (var j = 0; j < s.length; j++) {
              for (var i = 0; i < selectControl.layer.features.length; i++) {
                if (selectControl.layer.features[i].attributes.id == s[j].id) {
                  selectControl.layer.features[i].attributes.dontFocusGridPanel = true;
                  selectControl.highlight(selectControl.layer.features[i]);
                  selectControl.layer.features[i].attributes.dontFocusGridPanel = false;
                }
              }
            }
          }
        }
      })
      ,{
         region    : 'center'
        ,html      : '<div id="map"></div>'
        ,split     : true
        ,listeners : {
          afterrender : function(p) {
            initMap();
          }
          ,bodyresize : function(p,w,h) {
            var el = document.getElementById('map');
            if (el) {
              el.style.width  = w;
              el.style.height = h;
              map.updateSize();
            }
          }
        }
      }
    ]
  });
}

function initMap() {
  OpenLayers.Projection.addTransform("EPSG:4326","EPSG:3857",OpenLayers.Layer.SphericalMercator.projectForward);
  OpenLayers.Projection.addTransform("EPSG:3857","EPSG:4326",OpenLayers.Layer.SphericalMercator.projectInverse);
  map = new OpenLayers.Map('map',{
    layers            : [
       new OpenLayers.Layer.OSM(
         'OpenStreetMapOlay'
        ,'http://tile.openstreetmap.org/${z}/${x}/${y}.png'
        ,{
           isBaseLayer : false
        }
      )
      ,new OpenLayers.Layer.XYZ(
         'ESRI Ocean'
        ,'http://services.arcgisonline.com/ArcGIS/rest/services/Ocean_Basemap/MapServer/tile/${z}/${y}/${x}.jpg'
        ,{
           sphericalMercator : true
          ,isBaseLayer       : true
          ,wrapDateLine      : true
        }
      )
      ,new OpenLayers.Layer.Vector('queryHits',{
         rendererOptions : {zIndexing : true}
        ,styleMap        : new OpenLayers.StyleMap({
          'default' : new OpenLayers.Style(
            OpenLayers.Util.applyDefaults({
               strokeColor   : '#333DE4'
              ,strokeWidth   : 4
              ,strokeOpacity : 0.7
              ,fillColor     : '#333DE4'
              ,fillOpacity   : 0.7
              ,graphicZIndex : 10
              ,pointRadius   : 3
            })
          )
          ,'temporary' : new OpenLayers.Style(
            OpenLayers.Util.applyDefaults({
               strokeColor   : '#00FF00'
              ,strokeWidth   : 5
              ,fillColor     : '#00FF00'
              ,cursor        : 'pointer'
              ,graphicZIndex : 100
              ,pointRadius   : 5
            })
          )
          ,'select' : new OpenLayers.Style(
            OpenLayers.Util.applyDefaults({
               strokeColor   : '#FF0000'
              ,strokeWidth   : 5
              ,fillColor     : '#FF0000'
              ,cursor        : 'pointer'
              ,graphicZIndex : 100
              ,pointRadius   : 5
            })
          )
        })
      })
    ]
    ,projection        : proj900913
    ,displayProjection : proj4326
    ,units             : 'm'
    ,maxExtent         : new OpenLayers.Bounds(-20037508,-20037508,20037508,20037508.34)
  });

  map.addControl(new OpenLayers.Control.Graticule({
     labelFormat     : 'dms'
    ,layerName       : 'grid'
    ,labelSymbolizer : {
       fontColor   : "#666"
      ,fontSize    : "10px"
      ,fontFamily  : "tahoma,helvetica,sans-serif"
    }
    ,lineSymbolizer  : {
       strokeWidth     : 0.40
      ,strokeOpacity   : 0.90
      ,strokeColor     : "#999999"
      ,strokeDashstyle : "dash"
    }
  }));

  map.setCenter(new OpenLayers.LonLat(mapCenterAndZoom.lon,mapCenterAndZoom.lat).transform(proj4326,proj900913),mapCenterAndZoom.zoom);

  highlightControl = new OpenLayers.Control.SelectFeature(map.getLayersByName('queryHits')[0],{
     highlightOnly  : true
    ,hover          : true
    ,renderIntent   : 'temporary'
    ,eventListeners : {
      beforefeaturehighlighted : function(e) {
        var el = getOpenLayersElement(e);
        if (el && !el.toolTip) {
          el.toolTip = new Ext.ToolTip({
             title        : e.feature.attributes.title
            ,html         : '<table class="popup">'
              + '<tr><td>' + e.feature.attributes.abstract + '</td></tr>'
              + '</table>'
            ,target       : el
            ,showDelay    : 0
            ,hideDelay    : 0
            ,dismissDelay : 2000
            ,hideMode     : 'offsets'
            ,baseCls      : 'custom-x-tip'
            ,width        : 280
            ,closable     : true
            ,featureId    : e.feature.attributes.id
            ,listeners    : {
              // make sure only one TT is showing (FF has a problem otherwise)
              beforeshow : function(tt) {
                for (var i = 0; i < toolTipQueue.length; i++) {
                  var oldTt =  Ext.getCmp(toolTipQueue[i]);
                  if (oldTt) {
                    oldTt.hide();
                  }
                }
                toolTipQueue.push(tt.id);
                knownToolTips.push(tt);
              }
              ,hide : function(tt) {
                for (var i = 0; i < toolTipQueue.length; i++) {
                  if (toolTipQueue[i] == tt.id) {
                    toolTipQueue.splice(i,1);
                  }
                }
              }
            }
          });
        }
      }
    }
  });
  map.addControl(highlightControl);
  highlightControl.activate();

  selectControl = new OpenLayers.Control.SelectFeature(map.getLayersByName('queryHits')[0],{
    eventListeners : {
      featurehighlighted : function(e) {
        if (!e.feature.attributes.dontFocusGridPanel) {
          goQueryGridPanelRowById(e.feature.attributes.id,true);
        }
      }
      ,featureunhighlighted : function(e) {
        Ext.getCmp('searchResultsGridPanel').getSelectionModel().clearSelections();
      }
    }
  });
  map.addControl(selectControl);
  selectControl.activate();

  map.events.register('moveend',this,function() {
    var cmpField = Ext.getCmp('anyTextSearchField');
    if (cmpField) {
      var cmpButton = Ext.getCmp('buttonSyncWithMap');
      if (cmpButton && cmpButton.pressed) {
        cmp.onTrigger2Click();
      }
    }
    map.getLayersByName('OpenStreetMapOlay')[0].setVisibility(map.baseLayer.name == 'ESRI Ocean' && map.getZoom() >= 11);
  });
}

function isoDateToDate(s) {
  // 2010-01-01T00:00:00Z
  s = s.replace("\n",'');
  var p = s.split('T');
  if (p.length == 2) {
    var ymd = p[0].split('-');
    var hm = p[1].split(':');
    return new Date(
       ymd[0]
      ,ymd[1] - 1
      ,ymd[2]
      ,hm[0]
      ,hm[1]
    );
  }
  else {
    return false;
  }
}

function getOpenLayersElement(e) {
  var el = document.getElementById('OpenLayers.Geometry.LineString_' + (Number(e.feature.id.split('_')[e.feature.id.split('_').length - 1]) + 1));
  if (!el) {
    el = document.getElementById('OpenLayers.Geometry.Point_' + (Number(e.feature.id.split('_')[e.feature.id.split('_').length - 1]) - 8));
  }
  if (!el) {
    el = document.getElementById('OpenLayers.Geometry.Point_' + (Number(e.feature.id.split('_')[e.feature.id.split('_').length - 1]) - 1));
  }
  return el;
}

function goQueryGridPanelRowById(gpId,focus) {
  var gp  = Ext.getCmp('searchResultsGridPanel');
  var sto = gp.getStore();
  var idx = 0;
  sto.each(function(rec) {
    if (rec.id == gpId) {
      var sm = gp.getSelectionModel();
      sm.suspendEvents();
      sm.selectRow(idx);
      sm.resumeEvents();
      if (focus) {
        gp.getView().focusRow(idx);
      }
    }
    idx++;
  });
}

function goGetCaps(u,id) {
  if (new RegExp(/service=sos/i).test(u)) {
    sosGetCaps(u,id);
  }
  else {
    Ext.util.Cookies.set('getCapsUrl',u);
    setTimeout('checkNewGetCaps()',2000);
  }
}

function checkNewGetCaps() {
  var u = Ext.util.Cookies.get('getCapsUrl');
  if (u != '') {
    Ext.util.Cookies.set('getCapsUrl','');
    Ext.Msg.buttonText.ok = 'Close';
    Ext.Msg.alert('Map issue',"It appears that you have had a map reqeust in the queue for a bit.  This could be because you do not have the companion interactive map open.  Click <a target=_blank href='/getcaps/?url=" + encodeURIComponent(u) + "'>here</a> to open it in a new window.");
    Ext.Msg.buttonText.ok = 'OK';
  }
}

function sosGetCaps(url,id) {
  function sosGetCapsCallback(sto,id,r) {
    var caps = new OpenLayers.Format.SOSCapabilities().read(r.responseText);
    if (
      !caps 
      || !caps.contents
      || !caps.contents.offeringList
    ) {
      Ext.Msg.alert('SOS exception','There was an error querying this data service.');
      Ext.getCmp('searchResultsGridPanel').getEl().unmask();
      return;
    }
    var parentRec = sto.getAt(sto.findExact('cswId',id));
    var recs = [];
    for (var i in caps.contents.offeringList) {
      var bbox = caps.contents.offeringList[i].bounds.toArray();
      recs.push(new sto.recordType({
         title      : i + ' @ ' + parentRec.get('title')
        ,provider   : parentRec.get('provider')
        ,abstract   : caps.contents.offeringList[i].observedProperties.length > 0 ? 'Observed property(ies): ' + caps.contents.offeringList[i].observedProperties.join(', ') : ''
        ,cswId      : '___' + parentRec.get('cswId')
        ,bboxWest   : bbox[0]
        ,bboxEast   : bbox[2]
        ,bboxNorth  : bbox[3]
        ,bboxSouth  : bbox[1]
        ,minT       : caps.contents.offeringList[i].time.timePeriod.beginPosition.replace('.000Z','Z')
        ,maxT       : caps.contents.offeringList[i].time.timePeriod.endPosition.replace('.000Z','Z')
        ,services   : {}
        ,dimensions : {}
      }));
    }
    sto.insert(sto.findExact('cswId',id) + 1,recs);
    Ext.getCmp('searchResultsGridPanel').getEl().unmask();
    syncMapWithResults(sto);
  }

  var sto = Ext.getCmp('searchResultsGridPanel').getStore();
  if (sto.findExact('cswId','___' + sto.getAt(sto.findExact('cswId',id)).get('cswId')) >= 0) {
    Ext.Msg.alert('Map error',"You cannot add these observations to the map more than once.");
  }
  else {
    Ext.getCmp('searchResultsGridPanel').getEl().mask('<table><tr><td>Loading...&nbsp;</td><td><img src="js/ext-3.3.0/resources/images/default/grid/loading.gif"></td></tr></table>','mask');
  OpenLayers.Request.issue({
         url      : 'sosGetCaps.php?u=' + encodeURIComponent(url)
      ,callback : OpenLayers.Function.bind(sosGetCapsCallback,null,sto,id)
    });
  }
}

function syncMapWithResults(sto) {
  activeSearches--;
  if (activeSearches <= 0) {
    Ext.getCmp('searchResultsGridPanel').getEl().unmask();
  }
  var lyr = map.getLayersByName('queryHits')[0];
  var features = [];
  sto.each(function(rec) {
    var g = {
       type        : 'Polygon'
      ,coordinates : [[
         [rec.get('bboxWest'),rec.get('bboxSouth')]
        ,[rec.get('bboxEast'),rec.get('bboxSouth')]
        ,[rec.get('bboxEast'),rec.get('bboxNorth')]
        ,[rec.get('bboxWest'),rec.get('bboxNorth')]
        ,[rec.get('bboxWest'),rec.get('bboxSouth')]
      ]]
    };
    var geojson = new OpenLayers.Format.GeoJSON();
    var f       = geojson.read({
       type     : 'FeatureCollection'
      ,features : [{
         type       : 'Feature'
        ,geometry   : g
        ,properties : {
           title    : rec.get('title')
          ,id       : rec.id
          ,abstract : rec.get('abstract') != '' ? rec.get('abstract') : 'no details available'
        }
      }]
    });
    f[0].geometry.transform(proj4326,proj900913);
    // change geometry from polygon to line
    if (f[0].geometry.getArea() == 0) {
      f[0].geometry = f[0].geometry.getVertices()[0];
    }
    else {
      var vertices = f[0].geometry.getVertices();
      vertices.push(vertices[0]);
      f[0].geometry = new OpenLayers.Geometry.LineString(vertices);
    }
    features.push(f[0]);
  });
  lyr.removeFeatures(lyr.features);
  lyr.addFeatures(features);
  lyr.redraw();
}
